#ifndef SEMINIX_PRINTK_H
#define SEMINIX_PRINTK_H

#include <utils/types.h>
#include <seminix/linkage.h>
#include <seminix/printk_levels.h>

extern __printf(1, 2) void panic(const char *fmt, ...) __noreturn __cold;

asmlinkage __printf(1, 2) __cold int printk(const char *fmt, ...);

#define no_printk(fmt, ...)				\
({							\
    if (0)						\
        printk(fmt, ##__VA_ARGS__);		\
    0;						\
})

static inline int printk_get_level(const char *buffer)
{
    if (buffer[0] == KERN_SOH_ASCII && buffer[1]) {
        switch (buffer[1]) {
        case '0' ... '7':
        case 'd':	/* KERN_DEFAULT */
        case 'c':	/* KERN_CONT */
            return buffer[1];
        }
    }
    return 0;
}

static inline const char *printk_skip_level(const char *buffer)
{
    if (printk_get_level(buffer))
        return buffer + 2;

    return buffer;
}

static inline const char *printk_skip_headers(const char *buffer)
{
    while (printk_get_level(buffer))
        buffer = printk_skip_level(buffer);

    return buffer;
}

#ifndef pr_fmt
#define pr_fmt(fmt) fmt
#endif

#define pr_emerg(fmt, ...) \
    printk(KERN_EMERG pr_fmt(fmt), ##__VA_ARGS__)
#define pr_alert(fmt, ...) \
    printk(KERN_ALERT pr_fmt(fmt), ##__VA_ARGS__)
#define pr_crit(fmt, ...) \
    printk(KERN_CRIT pr_fmt(fmt), ##__VA_ARGS__)
#define pr_err(fmt, ...) \
    printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__)
#define pr_warn(fmt, ...) \
    printk(KERN_WARNING pr_fmt(fmt), ##__VA_ARGS__)
#define pr_notice(fmt, ...) \
    printk(KERN_NOTICE pr_fmt(fmt), ##__VA_ARGS__)
#define pr_info(fmt, ...) \
    printk(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__)
#define pr_cont(fmt, ...) \
    printk(KERN_CONT fmt, ##__VA_ARGS__)

#ifdef DEBUG
#define pr_debug(fmt, ...) \
    printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
#else
#define pr_debug(fmt, ...) \
    no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
#endif

#endif /* !SEMINIX_PRINTK_H */
